﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Che300
{
    public class BaseCrawler : ICrawler
    {
        public event EventHandler<OnStartEventArgs> OnStart;
        public event EventHandler<OnCompletedEventArgs> OnCompleted;
        public event EventHandler<OnErrorEventArgs> OnError;
        public CookieContainer CookieContainer { get; set; }//定义cookie容器
        #region Che300评估
        /// <summary>
        /// 异步创建爬虫
        /// </summary>
        /// <param name="uri">爬取地址</param>
        /// <param name="proxy">代理服务器</param>
        /// <returns></returns>
        public async Task<string> Start(Uri uri, WebProxy proxy = null)
        {
            return await Task.Run(() =>
            {
                var pageSource = string.Empty;
                try
                {
                    if (OnStart != null) OnStart(this, new OnStartEventArgs(uri));
                    var watch = new Stopwatch();//获取运行时间
                    watch.Start();//开始计时
                    var requst = (HttpWebRequest)WebRequest.Create(uri);//创建请求
                    requst.Accept = "*/*";//设置Accept http标头的值
                    requst.ServicePoint.Expect100Continue = false;//加快载入速度
                    requst.ServicePoint.UseNagleAlgorithm = false;//禁用nagle算法加快载入速度
                    requst.AllowWriteStreamBuffering = false;//禁用缓冲
                    requst.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");//定义gzip压缩页面支持
                    //requst.ContentType = "application/x-www-form-urlencoded";//定义文档类型及编码
                    requst.ContentType = "application/json";
                    //  requst.ContentType = "text/plain; charset=gb2312";
                    requst.AllowAutoRedirect = false;//禁止重定向
                    requst.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";//设置user-agent 伪装成 chrom浏览器
                    requst.Timeout = 5000;//定义请求超时时间为5s
                    requst.KeepAlive = true;//建立持续链接
                    requst.Method = "GET";//定义请求方式
                    if (proxy != null) requst.Proxy = proxy;//设置代理服务器ip，伪装请求地址
                    requst.CookieContainer = CookieContainer;//附加cookie容器
                    requst.ServicePoint.ConnectionLimit = int.MaxValue;//定义最大连接数
                    using (var response = (HttpWebResponse)requst.GetResponse())//获取请求响应
                    {
                        foreach (Cookie cookie in response.Cookies) CookieContainer.Add(cookie);//将cookie  加入容器，保持登录
                        {
                            if (response.ContentEncoding.ToLower().Contains("gzip"))//解压{
                            {
                                using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
                                {
                                    using (StreamReader reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
                                    {
                                        pageSource = reader.ReadToEnd();
                                    }
                                }
                            }
                            else
                            {
                                using (Stream stream = response.GetResponseStream())
                                {
                                    using (StreamReader reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
                                    {
                                        pageSource = reader.ReadToEnd();
                                    }
                                }
                            }
                        }
                    }
                    requst.Abort();//取消请求
                    watch.Stop();//结束计时
                    var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;//获取当前线程id
                    var milliseconds = watch.ElapsedMilliseconds;//获取请求时长
                    if (OnCompleted != null) OnCompleted(this, new OnCompletedEventArgs(uri, threadId, milliseconds, pageSource));
                }
                catch (Exception ex)
                {
                    if (this.OnStart != null) this.OnError(this, new OnErrorEventArgs(uri, ex));
                }
                return pageSource;
            });
        }
        #endregion
        #region 二手车之家 评估
        public async Task<string> ErStart(Uri uri, WebProxy proxy = null)
        {
            return await Task.Run(() =>
            {
                var pageSource = string.Empty;
                try
                {
                    if (OnStart != null) OnStart(this, new OnStartEventArgs(uri));
                    var watch = new Stopwatch();//获取运行时间
                    watch.Start();//开始计时
                    var requst = (HttpWebRequest)WebRequest.Create(uri);//创建请求
                    requst.Accept = "*/*";//设置Accept http标头的值
                    requst.ServicePoint.Expect100Continue = false;//加快载入速度
                    requst.ServicePoint.UseNagleAlgorithm = false;//禁用nagle算法加快载入速度
                    requst.AllowWriteStreamBuffering = false;//禁用缓冲
                    requst.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");//定义gzip压缩页面支持
                    //requst.ContentType = "application/x-www-form-urlencoded";//定义文档类型及编码
                    requst.ContentType = "application/json";
                    //  requst.ContentType = "text/plain; charset=gb2312";
                    requst.AllowAutoRedirect = false;//禁止重定向
                    requst.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";//设置user-agent 伪装成 chrom浏览器
                    requst.Timeout = 5000;//定义请求超时时间为5s
                    requst.KeepAlive = true;//建立持续链接
                    requst.Method = "GET";//定义请求方式
                    if (proxy != null) requst.Proxy = proxy;//设置代理服务器ip，伪装请求地址
                    requst.CookieContainer = CookieContainer;//附加cookie容器
                    requst.ServicePoint.ConnectionLimit = int.MaxValue;//定义最大连接数
                    using (var response = (HttpWebResponse)requst.GetResponse())//获取请求响应
                    {
                        foreach (Cookie cookie in response.Cookies) CookieContainer.Add(cookie);//将cookie  加入容器，保持登录
                        {
                            if (response.ContentEncoding.ToLower().Contains("gzip"))//解压{
                            {
                                using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
                                {
                                    using (StreamReader reader = new StreamReader(stream, Encoding.GetEncoding("gb2312")))
                                    {
                                        pageSource = reader.ReadToEnd();
                                    }
                                }
                            }
                            else
                            {
                                using (Stream stream = response.GetResponseStream())
                                {
                                    using (StreamReader reader = new StreamReader(stream, Encoding.GetEncoding("gb2312")))
                                    {
                                        pageSource = reader.ReadToEnd();
                                    }
                                }
                            }
                        }
                    }
                    requst.Abort();//取消请求
                    watch.Stop();//结束计时
                    var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;//获取当前线程id
                    var milliseconds = watch.ElapsedMilliseconds;//获取请求时长
                    if (OnCompleted != null) OnCompleted(this, new OnCompletedEventArgs(uri, threadId, milliseconds, pageSource));
                }
                catch (Exception ex)
                {
                    if (this.OnStart != null) this.OnError(this, new OnErrorEventArgs(uri, ex));
                }
                return pageSource;
            });
        }
        #endregion
    }
    /// <summary>
    /// 爬虫完成
    /// </summary>
    public class OnCompletedEventArgs
    {
        public Uri Uri { get; private set; }
        public int ThreadId { get; private set; }
        public string PageSource { get; private set; }
        public long Milliseconds { get; private set; }
        public OnCompletedEventArgs(Uri uri, int threadId, long millisecomds, string pagesource)
        {
            Uri = uri;
            ThreadId = threadId;
            PageSource = pagesource;
            Milliseconds = millisecomds;
        }
    }
    /// <summary>
    /// 爬虫异常
    /// </summary>
    public class OnErrorEventArgs
    {
        public Uri Uri { get; set; }
        public Exception Exception { get; set; }
        public OnErrorEventArgs(Uri uri, Exception exception)
        {
            Uri = uri;
            Exception = exception;
        }
    }
    /// <summary>
    /// 爬虫开始
    /// </summary>
    public class OnStartEventArgs
    {
        public Uri Uri { get; set; }
        public OnStartEventArgs(Uri uri)
        {
            Uri = uri;
        }
    }
    public interface ICrawler
    {
        event EventHandler<OnStartEventArgs> OnStart;
        event EventHandler<OnCompletedEventArgs> OnCompleted;
        event EventHandler<OnErrorEventArgs> OnError;
        Task<string> Start(Uri uri, WebProxy proxy);//异步
    }

}
